package org.twnmayberry.ejb;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.annotation.security.RolesAllowed;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Session;
import javax.jms.Topic;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.twndmv.dto.PersonDTO;
import org.twndmv.ejb.DmvTestUtilRemote;
import org.twndmv.ejb.PersonMgmtRemote;
import org.twnmayberry.bl.PoiMgmt;
import org.twnmayberry.blimpl.PoiMgmtImpl;
import org.twnmayberry.bo.POI;
import org.twnmayberry.bo.Sex;
import org.twnmayberry.bo.Type;
import org.twnmayberry.dao.POIDAO;
import org.twnmayberry.dto.ActivityDTO;
import org.twnmayberry.dto.DTOUtils;
import org.twnmayberry.dto.POIDTO;
import org.twnmayberry.jms.MayberryPublisher;
import org.twnmayberry.jpa.POIDAOImpl;

@Stateless
@RolesAllowed({ "mayberry-analytical","mayberry-admin","mayberry-tactical" })
public class PoiMgmtEJB implements PoiMgmtRemote {

	private static Log log = LogFactory.getLog(PoiMgmtEJB.class);

	@Resource(mappedName = "java:/JmsXA")
	private ConnectionFactory connFactory;
	@Resource(mappedName = "java:/topic/ejava/projects/datashare/mayberry-poi", type = Topic.class)
	private Destination poiTopic;

	@PersistenceContext(unitName = "mayberryEntity")
	private EntityManager em;

	private PoiMgmt poiManager;

	private MayberryPublisher mayberryPublisher;

	@EJB(lookup = "ejb:twnDmvEAR/twnDmvEJB/DmvTestUtilEJB!org.twndmv.ejb.DmvTestUtilRemote")
	private DmvTestUtilRemote dmvTestUtil;

	@EJB(lookup = "ejb:twnDmvEAR/twnDmvEJB/PersonMgmtEJB!org.twndmv.ejb.PersonMgmtRemote")
	private PersonMgmtRemote personManager;

	@PostConstruct
	public void init() {
		POIDAO poiDB = new POIDAOImpl(em);
		poiManager = new PoiMgmtImpl(poiDB);
		mayberryPublisher = new MayberryPublisher("PublisherEJB");
	}

	@Override
	@RolesAllowed({ "mayberry-tactical","mayberry-admin" })
	public void addPOI(POIDTO newPOI) {
		POI newGuy = DTOUtils.convertDTOtoPOI(newPOI);
		poiManager.addPOI(newGuy);
		boolean danger = poiManager.isDangerous(newGuy);
		publishPOIChange(newPOI, danger);
	}

	@Override
	@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
	@RolesAllowed({ "mayberry-tactical","mayberry-admin" })
	public void addPOIFromDMV(long dmvId) {

		PersonDTO resultPerson = personManager.getPersonByID(dmvId);
		POIDTO poi = new POIDTO();
		poi.setFirstName(resultPerson.getFirstName());
		poi.setMiddleName(resultPerson.getMiddleName());
		poi.setLastName(resultPerson.getLastName());
		poi.setGender(Sex.translate(resultPerson.getPhysicalDetails().getSEX()
				.name()));
		poi.setHeight(resultPerson.getPhysicalDetails().getHeight());
		poi.setWeight(resultPerson.getPhysicalDetails().getWeight());

		addPOI(poi);
	}

	@Override
	@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
	@RolesAllowed({ "mayberry-tactical","mayberry-admin" })
	public void addActivity(long poiID, ActivityDTO newActivity) {
		POI newActDude = poiManager.getPOI(poiID);
		newActDude.getActivities().add(
				DTOUtils.convertDTOtoActivity(newActivity));
		poiManager.updatePOI(newActDude);
		boolean danger = poiManager.isDangerous(newActDude);
		publishPOIChange(DTOUtils.convertPOItoDTO(newActDude), danger);
	}

	@Override
	@TransactionAttribute(TransactionAttributeType.REQUIRED)
	public POIDTO getPOI(long id) {
		return DTOUtils.convertPOItoDTO(poiManager.getPOI(id));
	}

	@Override
	@TransactionAttribute(TransactionAttributeType.REQUIRED)
	public List<POIDTO> getAllPOI() {
		List<POIDTO> results = new ArrayList<POIDTO>();

		for (POI dude : poiManager.getAllPOI()) {
			results.add(DTOUtils.convertPOItoDTO(dude));
		}

		return results;
	}

	@Override
	@TransactionAttribute(TransactionAttributeType.REQUIRED)
	public boolean isDangerous(POIDTO badGuy) {
		return poiManager.isDangerous(DTOUtils.convertDTOtoPOI(badGuy));
	}

	@Override
	@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
	@RolesAllowed({ "mayberry-admin" })
	public void populateDB() {
		Random random = new Random();
		for (int i = 0; i < 1000; i++) {
			POIDTO poi = new POIDTO();
			poi.setFirstName("Bob-" + i);
			poi.setMiddleName("Danger-" + i);
			poi.setLastName("Awesome-" + i);

			poi.setHeight(random.nextInt(200));
			poi.setWeight(random.nextInt(200));
			ActivityDTO newAct = new ActivityDTO();
			newAct.setDate(new Date(System.currentTimeMillis()));
			newAct.setType(Type.ASSAULT);
			if (i % 67 == 0) {
				newAct.setDescription("This dude is dangerous");
			} else {
				newAct.setDescription("This dude is weak");
			}
		}

		dmvTestUtil.populate();
	}

	@Override
	@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
	@RolesAllowed({ "mayberry-tactical","mayberry-admin" })
	public void addList(List<POIDTO> newPeeps) {

		for (POIDTO peep : newPeeps) {
			try {
				poiManager.addPOI(DTOUtils.convertDTOtoPOI(peep));
			} catch (Exception e) {
				log.error("Error adding POI list.  Rolling back the transaction: "
						+ e);
				em.getTransaction().rollback();
			}
		}

	}

	@Override
	public List<POIDTO> getPOIsByName(String firstName, String middleName,
			String lastName) {
		List<POIDTO> results = new ArrayList<POIDTO>();
		for (POI peep : poiManager.getPOIsByName(firstName, middleName,
				lastName)) {
			results.add(DTOUtils.convertPOItoDTO(peep));
		}
		return results;
	}

	@Override
	public void publishPOIChange(POIDTO poi, boolean dangerous) {
		Connection connection = null;
		Session session = null;
		try {
			connection = connFactory.createConnection();
			session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
			log.info("Publishing POI change...");
			mayberryPublisher.publishPOI(session, poiTopic, poi, dangerous);
		} catch (Exception e) {
			log.error("Error publishing POI change: " + e);
		} finally {
			if (connection != null) {
				try {
					connection.close();
				} catch (JMSException e) {
					log.error("Error closing connection: " + e);
				}
			}
			if (session != null) {
				try {
					session.close();
				} catch (JMSException e) {
					log.error("Error closing connection: " + e);
				}
			}
		}
	}

}
